package main

import (
	"bufio"
	"bytes"
	"database/sql"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"reflect"
	"strconv"
	"strings"
	"time"
)

// 定义一个结构体来映射JSON数据的结构
type Response struct {
	Parts []struct {
		Content []struct {
			Type   string `json:"type"`
			Text   string `json:"text"`
			Status string `json:"status"`
		} `json:"content"`
		Status string `json:"status"`
	} `json:"parts"`
}

type RefreshTokenResponseData struct {
	Status  int64  `json:"status"`
	Message string `json:"message"`
	Result  struct {
		UserID       string `json:"user_id"`
		AccessToken  string `json:"access_token"`
		RefreshToken string `json:"refresh_token"`
	} `json:"result"`
}

var accessToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI5ZDE1MjFkM2EwMDk0NzVmOWU3YTgxODQxOTIyNTY4NyIsImV4cCI6MTcxNjk2MjE2NiwibmJmIjoxNzE2ODc1NzY2LCJpYXQiOjE3MTY4NzU3NjYsImp0aSI6ImZjMmU4NTVmY2U1ODQzYWNiOTQxYWQ1YWY2Zjk2MzcyIiwidWlkIjoiNjY0YWU4NDY3MzM1OThiZGE5ZjdhYWQzIiwidHlwZSI6ImFjY2VzcyJ9.ETr3X2e7dWZ4iMbIwhrLug7W1fvEBDZG2I2Q3tloXwI"
var needRefreshAccessToken = true

func main() {

	go refreshTokenLoop()

	startApiService()

}

// isEmpty 检查一个结构体是否为空
func isEmpty(obj interface{}) bool {
	v := reflect.ValueOf(obj)
	if v.Kind() == reflect.Ptr {
		v = v.Elem()
	}
	return v.NumField() == 0 || reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface())
}

func refreshTokenLoop() {
	for {
		if needRefreshAccessToken {
			refreshTokenRequest()
		}
		time.Sleep(1000 * time.Millisecond)
	}
}

func refreshTokenRequest() {
	refreshToken := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmcmVzaCI6ZmFsc2UsImlhdCI6MTcxNjE4NTE1OSwianRpIjoiYWUxMDg2NmUtNDA3ZS00YWZkLTk4MTktYzAyOGUyZGFmNTVmIiwidHlwZSI6InJlZnJlc2giLCJzdWIiOiI5ZDE1MjFkM2EwMDk0NzVmOWU3YTgxODQxOTIyNTY4NyIsIm5iZiI6MTcxNjE4NTE1OSwiZXhwIjoxNzMxNzM3MTU5LCJ1aWQiOiI2NjRhZTg0NjczMzU5OGJkYTlmN2FhZDMiLCJ1cGxhdGZvcm0iOiJwYyIsInJvbGVzIjpbInVuYXV0aGVkX3VzZXIiXX0.ejCOPkLtEtW4cBY8tlzJ4nmoyzeg1RIg3DBCEhWNcbo"

	// 创建HTTP客户端
	client := &http.Client{}

	// 创建请求URL
	req, err := http.NewRequest("POST", "https://chatglm.cn/chatglm/user-api/user/refresh", nil)
	if err != nil {
		fmt.Println("请求创建失败：", err)
		return
	}

	// 设置请求头
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", refreshToken))

	// 发送请求
	resp, err := client.Do(req)
	if err != nil {
		fmt.Println("请求发送失败：", err)
		return
	}
	defer resp.Body.Close()

	// 读取响应
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Println("响应读取失败：", err)
		return
	}

	// 解析JSON响应
	var data RefreshTokenResponseData
	err = json.Unmarshal(body, &data)
	if err != nil {
		fmt.Println("JSON解析失败：", err)
		return
	}

	// 打印解析后的数据
	fmt.Println("状态：", data.Status)
	fmt.Println("消息：", data.Message)

	if !isEmpty(data.Result) {
		fmt.Println("用户ID：", data.Result.UserID)

		accessToken = data.Result.AccessToken
		needRefreshAccessToken = false
		fmt.Println("刷新token：", accessToken)
	}

}

func requestAI(promoteInfo map[string]string, callBack func(receiveInfo map[string]string)) {
	//请求一个AI 服务

	file_size, _ := strconv.ParseInt(promoteInfo["file_size"], 10, 64)

	promoteText := promoteInfo["text"]
	fileName := promoteInfo["file_name"]
	fileId := promoteInfo["file_id"]
	imageUrl := promoteInfo["image_url"]
	fileSize := file_size

	jsonStr := fmt.Sprintf(`{"assistant_id":"65940acff94777010aa6b796","conversation_id":"","meta_data":{"mention_conversation_id":"","is_test":false,"input_question_type":"xxxx","channel":"","draft_id":"","quote":""},"messages":[{"role":"user","content":[{"type":"text","text":"%s"},{"type":"image","image":[{"file_name":"%s","file_id":"%s","image_url":"%s","file_size":%d}]}]}]}`,
		promoteText, fileName, fileId, imageUrl, fileSize)

	// 创建一个HTTP客户端
	client := &http.Client{}

	// 创建一个请求
	req, err := http.NewRequest("POST", "https://chatglm.cn/chatglm/backend-api/assistant/stream", bytes.NewBuffer([]byte(jsonStr)))
	if err != nil {
		fmt.Println("Error creating request:", err)
		return
	}

	// 设置请求头
	req.Header.Set("Content-Type", "application/json")

	req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", accessToken))

	// 发送请求
	resp, err := client.Do(req)
	if err != nil {
		fmt.Println("Error sending request:", err)
		return
	}
	defer resp.Body.Close()

	// 使用bufio创建一个缓冲读取器
	reader := bufio.NewReader(resp.Body)

	// 循环读取响应体的数据
	fullText := ""
	for {
		line, err := reader.ReadString('\n')
		if err != nil {
			if err == io.EOF {
				// 读取到EOF，表示服务器已经关闭连接
				break
			}
			fmt.Println("Error reading response body:", err)
			return
		}
		fmt.Println("line:", line)
		if strings.HasPrefix(line, "data:") {
			jsonStr := strings.TrimPrefix(line, "data:")
			var r Response

			// 解析JSON数据
			err2 := json.Unmarshal([]byte(jsonStr), &r)
			if err2 != nil {
				log.Fatal("Error parsing JSON: ", err2)
			}

			// 打印content字段
			cType := ""
			cText := ""
			cStatus := ""
			for _, part := range r.Parts {
				for _, content := range part.Content {
					cType = content.Type
					cText = content.Text
					cStatus = content.Status
					fmt.Printf("Type: %s, Text: %s, Status: %s\n", cType, cText, cStatus)

				}
				if cStatus == "" {
					cStatus = part.Status
				}
			}

			//cText - fullText
			if len(cText) > 0 {
				startPos := len(fullText)
				endPos := len(cText)
				if endPos >= startPos {
					text_inc := ""
					text_inc = cText[startPos:endPos]
					callBack(map[string]string{
						"text_inc": text_inc,
						"status":   cStatus,
					})
					fullText = cText
					time.Sleep(50 * time.Millisecond)
				}

			}

			if cStatus == "finish" {
				//结束
				break
			}

		}

		//"code":401
		if strings.HasPrefix(line, `{"code":401`) {
			needRefreshAccessToken = true
			fmt.Println("请求401")
			callBack(map[string]string{
				"status": "failed",
			})
		}

	}

}

type PostParams struct {
	Category string `json:"category"`
	FileName string `json:"file_name"`
	FileId   string `json:"file_id"`
	ImageUrl string `json:"image_url"`
}

// 启动API服务
func startApiService() {
	http.HandleFunc("/test_stream", streamHandler)
	http.HandleFunc("/test_api", testApiHandler)
	port := 8080
	fmt.Println("listen to:", port)
	log.Fatal(http.ListenAndServe(fmt.Sprintf("0.0.0.0:%d", port), nil))
}

func testApiHandler(w http.ResponseWriter, r *http.Request) {
	query := r.URL.Query()
	name := query.Get("name")

	fmt.Fprintf(w, "Hello server, %s!", name)
}

func streamHandler(w http.ResponseWriter, r *http.Request) {

	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		fmt.Printf("Couldn't read request body:", http.StatusBadRequest)
		http.Error(w, "Couldn't read request body", http.StatusBadRequest)
		return
	}

	// 关闭 body 以释放资源
	defer r.Body.Close()

	// 将 JSON 数据解析到结构体实例中
	var params PostParams
	if err := json.Unmarshal(body, &params); err != nil {
		fmt.Println("Couldn't parse JSON:", err)
		fmt.Println("req string:", string(body))
		http.Error(w, "Couldn't parse JSON", http.StatusBadRequest)
		return
	}

	// 使用解析后的参数
	fmt.Printf("Received: %+v\n", params)

	// 保存到mysql,以便统计
	// FileName FileId image_url

	// 设置HTTP头，允许流式传输
	w.Header().Set("Content-Type", "text/event-stream")
	w.Header().Set("Cache-Control", "no-cache")
	w.Header().Set("Connection", "keep-alive")

	// 创建一个只写关闭的缓冲区
	flusher, ok := w.(http.Flusher)
	if !ok {
		http.Error(w, "Streaming unsupported!", http.StatusInternalServerError)
		return
	}

	// go func() {
	// 	// 向客户端发送数据流
	// 	for i := 0; i < 10; i++ {
	// 		time.Sleep(time.Second)
	// 		fmt.Fprintf(w, "来自服务器: %d\n\n", i)
	// 		flusher.Flush()
	// 	}
	// }()

	//go func() {

	promoteText := ""
	var cate string = params.Category
	switch {
	case cate == "botany":
		promoteText = "图中主要植物是什么？尽量识别准确。输出关于它的详细信息，重点从科学环境人文角度进行论述，如植物学分类，分布区域，培育技术，经济药用价值，病虫害防治，人文历史故事"
	case cate == "animal":
		promoteText = "图中主要动物是什么？尽量识别准确。输出关于它的详细信息，重点从生态角度进行论述,如动物学分类，分布区域，生长环境食物习性，与人类的关系，文化故事"
	case cate == "food":
		promoteText = "图中主要食物是什么？尽量识别准确。输出关于它的详细信息，重点从保健、文化传承角度进行论述,如食谱分类，国家地域，制作流程，人文地域故事"
	case cate == "mineral":
		promoteText = "图中主要矿石是什么？尽量识别准确。输出关于它的详细信息，重点从科学历史角度进行论述,如矿物分类，地层分布，利用价值，文化故事"
	case cate == "architecture":
		promoteText = "图中主要建筑是什么？尽量识别准确。输出关于它的详细信息，重点从文艺历史角度进行论述,如建筑分类，国家地域，建筑师，建筑技术，历史故事"
	case cate == "machine":
		promoteText = "图中主要机械是什么？尽量识别准确。输出关于它的详细信息，重点从科技创新角度进行论述,如机械分类，品牌，发明家，制造技术，工具用途"

	default:
		fmt.Printf("差\n")
	}

	promoteInfo := map[string]string{
		"text":      promoteText,
		"file_name": params.FileName,
		"file_id":   params.FileId,
		"image_url": params.ImageUrl,
		"file_size": "0",
	}
	requestAI(promoteInfo, func(receiveInfo map[string]string) {
		status := receiveInfo["status"]
		text_inc := receiveInfo["text_inc"]
		fmt.Fprintf(w, text_inc)
		flusher.Flush()

		if status == "finish" {
			fmt.Fprintf(w, "stream_api_finished")
			flusher.Flush()
		} else if status == "failed" {
			fmt.Fprintf(w, "stream_api_failed")
			flusher.Flush()
		}
	})
	//}()

	//select {}

	/*
		// 读取客户端发送的数据流
		r.Body = http.MaxBytesReader(w, r.Body, 1048576) // 限制最大读取大小
		reader := r.Body
		b := make([]byte, 1024)
		ch := make(chan string)
		go func() {
			defer close(ch)
			for {
				n, err := reader.Read(b)
				if err != nil && err != io.EOF {
					log.Println("Error reading request body:", err)
					return
				}
				if n == 0 {
					break
				}
				// 处理接收到的数据，并可能发送回复
				ch <- string(b[:n])
			}
		}()

		// 在单独的goroutine中保持连接打开
		go func() {
			for event := range ch {
				// 假设我们简单地将接收到的数据发送回客户端
				fmt.Fprintf(w, "data: %s\n\n", event)
				flusher.Flush() // 确保发送缓冲区中的内容
			}
		}()

		// 阻塞，直到关闭通道
		<-ch
	*/
}

func saveUploadInfo(params PostParams) {
	//params.FileName,
	//"file_id" : params.FileId,
	//"image_url" : params.ImageUrl,
	// 连接到MySQL数据库
	db, err := sql.Open("mysql", "user:password@tcp(localhost:3306)/dbname")
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	// 确保数据库连接是活的
	err = db.Ping()
	if err != nil {
		log.Fatal(err)
	}

	// 插入文件信息到数据库
	_, err = db.Exec("INSERT INTO files (file_id, file_name, image_url) VALUES (?, ?, ?)", params.FileId, params.FileName, params.ImageUrl)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println("Successfully inserted file information into the database")

}
